package com.qf.service.impl;

import com.alibaba.druid.util.StringUtils;
import com.qf.Movie;
import com.qf.ResultVo;
import com.qf.dto.SearchDTO;
import com.qf.service.MovieSearchService;
import com.qf.vo.PageResultVo;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 作者：Xx凯丶
 * 时间：2022/4/19 15:14
 */
@Service
public class MovieSearchServiceImpl implements MovieSearchService {
    @Autowired
    private ElasticsearchRestTemplate template;
    @Override
    public List<Movie> findAllMovie() {
        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
        NativeSearchQuery query = new NativeSearchQueryBuilder()
                .withQuery(matchAllQueryBuilder)
                .build();
        SearchHits<Movie> searchRes = template.search(query, Movie.class);
        List<SearchHit<Movie>> searchHits = searchRes.getSearchHits();
        List<Movie> movies = searchHits.stream().map(hit -> hit.getContent()).collect(Collectors.toList());
        return movies;
    }

    @Override
    public Map<String,List<String>> findBucket() {
        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
        TermsAggregationBuilder typeAggregationBuilder = AggregationBuilders.terms("type").field("types").size(100);
        TermsAggregationBuilder placeAggregationBuilder = AggregationBuilders.terms("place").field("showPlace").size(100);
        NativeSearchQuery query = new NativeSearchQueryBuilder()
                .withQuery(matchAllQueryBuilder)
                .addAggregation(typeAggregationBuilder)
                .addAggregation(placeAggregationBuilder)
                .build();
        SearchHits<Movie> searchRes = template.search(query, Movie.class);
        List<SearchHit<Movie>> searchHits = searchRes.getSearchHits();
        Aggregations aggregations = searchRes.getAggregations();
        Terms type = aggregations.get("type");

        List<String> types = type.getBuckets().stream().map(item -> (String) item.getKey()).collect(Collectors.toList());
        Terms place = aggregations.get("place");
        List<String> places = place.getBuckets().stream().map(item -> (String) item.getKey()).collect(Collectors.toList());

        return new HashMap(){{
            put("type",types);
            put("place",places);
        }};
    }

    @Override
    public PageResultVo<Movie> search(SearchDTO searchDTO) {
        if (searchDTO == null) {
            return  new PageResultVo<>(false,"非法参数");
        }
        String keyword = searchDTO.getKeyword();
        String typeFilter = searchDTO.getTypeFilter();
        String placeFilter = searchDTO.getPlaceFilter();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if(!StringUtils.isEmpty(keyword)){
            if(!keyword.equals("")){
                MatchQueryBuilder movieCh = QueryBuilders.matchQuery("movieCh", keyword);
                boolQueryBuilder.must(movieCh);
            }

        }
        if(!StringUtils.isEmpty(typeFilter)){
            if (!typeFilter.equals("")){
                MatchQueryBuilder types = QueryBuilders.matchQuery("types",  typeFilter);
                boolQueryBuilder.must(types);
            }

        }
        if(!StringUtils.isEmpty(placeFilter)){
            if(!placeFilter.equals("")){
                MatchQueryBuilder showPlace = QueryBuilders.matchQuery("showPlace", placeFilter);
                boolQueryBuilder.must(showPlace);
            }
        }
        PageRequest pageRequest = PageRequest.of((searchDTO.getPage() - 1) < 0 ? 0 : (searchDTO.getPage() - 1), searchDTO.getSize());
        TermsAggregationBuilder typeAggregationBuilder = AggregationBuilders.terms("type").field("types").size(100);
        TermsAggregationBuilder placeAggregationBuilder = AggregationBuilders.terms("place").field("showPlace").size(100);

        if(!StringUtils.isEmpty(typeFilter)){
            TermQueryBuilder types = QueryBuilders.termQuery("types", typeFilter);
            boolQueryBuilder.filter(types);
        }

        if(!StringUtils.isEmpty(placeFilter)){
            TermQueryBuilder place = QueryBuilders.termQuery("showPlace", placeFilter);
            boolQueryBuilder.filter(place);
        }
        Integer movieStatusFilter = searchDTO.getMovieStatusFilter();
        if(movieStatusFilter!=null){
            TermQueryBuilder place = QueryBuilders.termQuery("movieStatus", movieStatusFilter);
            boolQueryBuilder.filter(place);
        }
        String movieNumSort = searchDTO.getMovieNumSort();
        FieldSortBuilder movieNumFieldSortBuilder = null;
        if(!StringUtils.isEmpty(movieNumSort)){
            if("asc".equals(movieNumSort)){
                movieNumFieldSortBuilder = SortBuilders.fieldSort("movieNum").order(SortOrder.ASC);
            }else{
                movieNumFieldSortBuilder = SortBuilders.fieldSort("movieNum").order(SortOrder.DESC);
            }
        }
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
                //指定查询方式
                .withQuery(boolQueryBuilder)
                .withPageable(pageRequest)
                .addAggregation(typeAggregationBuilder)
                .addAggregation(placeAggregationBuilder);
        if(movieNumFieldSortBuilder != null){
            nativeSearchQueryBuilder.withSort(movieNumFieldSortBuilder);
        }
        SearchHits<Movie> searchRes = template.search(nativeSearchQueryBuilder.build(), Movie.class);
        //获取总记录数
        long totalHits = searchRes.getTotalHits();
        List<Movie> movies = searchRes.stream().map(hit -> hit.getContent()).collect(Collectors.toList());
        Aggregations aggregations = searchRes.getAggregations();
        Terms type = aggregations.get("type");

        List<String> types = type.getBuckets().stream().map(item -> (String) item.getKey()).collect(Collectors.toList());
        Terms place = aggregations.get("place");
        List<String> places = place.getBuckets().stream().map(item -> (String) item.getKey()).collect(Collectors.toList());
        PageResultVo<Movie> pageResultVo = new PageResultVo<>(true, "success");
        pageResultVo.setTotal(totalHits);
        pageResultVo.setData(movies);
        pageResultVo.setTypes(types);
        pageResultVo.setPlaces(places);
        return pageResultVo;
    }
}
